/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2024-05-20 17:18:50
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 12:54:06
 * @FilePath     : \openchaoji-corelib\secc\utility\OpenChaoJi_secc_utility_pilot.c
 * @Description  : 本文件定义SECC Utility层 Pilot 导引电路识别 模块
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "OpenChaoJi_secc_utility_pilot.h"

/**
 * @brief 本模块的上下文数据结构
 */
struct OpenChaoJi_secc_context_utility_pilot {
    int tag;

	/**
     * 本SECC使用的系统类型, 目前仅支持A/B两类
     * 由于SECC不支持切换系统, 所以对端的EVCC类型必然跟SECC类型匹配
    */
    enum OpenChaoJi_secc_gbt27930_type secc_gbt27930_type;
	/**
	 * hal层句柄
	 */
	OpenChaoJi_hal_handle hal_handle;

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    bool permit_charge;
#endif

    /**
     * Pilot 导引电路识别状态
     * SECC类型确定后必然使用一种状态
     */
    union
    {
        enum OpenChaoJi_pilot_status_gbt18487_a pilot_status_gbt18487_a;
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
        enum OpenChaoJi_pilot_status_gbt18487_b pilot_status_gbt18487_b;
#endif
    } pilot_status;

    /**
     * 检测点1电压
     */
    int voltage_checkpoint_1;
};

/**
 * @brief 初始化
 *
 * @param info 初始化信息
 * @return 成功返回创建的上下文指针，失败返回NULL。
 */
struct OpenChaoJi_secc_context_utility_pilot * OpenChaoJi_secc_utility_pilot_init(const struct OpenChaoJi_secc_create_info_utility_pilot * info)
{
    struct OpenChaoJi_secc_context_utility_pilot *context = NULL;

    context = (struct OpenChaoJi_secc_context_utility_pilot *)OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_secc_context_utility_pilot));
    if(context == NULL)
    {
        return NULL;
    }
    memset(context,0,sizeof(struct OpenChaoJi_secc_context_utility_pilot));

    context->tag = info->tag;
    context->secc_gbt27930_type = info->secc_gbt27930_type;
    context->hal_handle = info->hal_handle;

    OpenChaoJi_secc_utility_pilot_reset(context);

    return context;
}

/**
 * @brief 销毁
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_secc_utility_pilot_term(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return -1;
    }

    OpenChaoJi_os_free(context);

    return 0;
}

/**
 * @brief 复位
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_secc_utility_pilot_reset(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return -1;
    }

    LOG_WARNING("[%d]Pilot Reset", context->tag);

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    context->permit_charge = false;
    if(OPENCHAOJI_SECC_GBT27930_TYPE_B == context->secc_gbt27930_type)
    {
        context->pilot_status.pilot_status_gbt18487_b = OPENCHAOJI_PILOT_STATUS_GBT18487_B_A;
    }
#endif
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if(OPENCHAOJI_SECC_GBT27930_TYPE_A == context->secc_gbt27930_type)
    {
        context->pilot_status.pilot_status_gbt18487_a = OPENCHAOJI_PILOT_STATUS_GBT18487_A_DISCONNECT;
    }
#endif
    context->voltage_checkpoint_1 = 0;

    return 0;
}

/**
 * @brief secc允许充电, B类系统需要, A类无此功能
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_secc_utility_pilot_b_permit_charge(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return -1;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if(OPENCHAOJI_SECC_GBT27930_TYPE_B == context->secc_gbt27930_type)
    {
        OpenChaoJi_secc_hal_gbt_b_close_s1(context->hal_handle,1);
        context->permit_charge = true;
        return 0;
    }
#endif

    return -1;
}

/**
 * @brief 获取secc的导引状态, 用于判断是否连接, 是否已经确认可以充电等(导引方式, 数据通信另外判断)
 * 		  system调用本方法时, 需要确定当前配置的SECC类型后再进行调用, 即该方法二选一调用
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 已连接返回1，未连接返回0
 */

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
enum OpenChaoJi_pilot_status_gbt18487_a OpenChaoJi_secc_utility_pilot_status_a(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    enum OpenChaoJi_pilot_status_gbt18487_a status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_UNKNOWN;
    int volt_value = 0;

    if(context == NULL)
    {
        return OPENCHAOJI_PILOT_STATUS_GBT18487_A_UNKNOWN;
    }

    if (OPENCHAOJI_SECC_GBT27930_TYPE_A == context->secc_gbt27930_type)
    {
        volt_value = OpenChaoJi_secc_hal_gbt_get_vol_checkpoint_1(context->hal_handle);
        if(volt_value <= SYSTEM_A_EVCC_CC2_VOLT_11_2V && volt_value >= SYSTEM_A_EVCC_CC2_VOLT_12_8V)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_DISCONNECT;
        }
        else if(volt_value <= SYSTEM_A_EVCC_CC2_VOLT_5_2V && volt_value >= SYSTEM_A_EVCC_CC2_VOLT_6_8V)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_S1_OPEN;
        }
        else if(volt_value <= SYSTEM_A_EVCC_CC2_VOLT_4_8V && volt_value >= SYSTEM_A_EVCC_CC2_VOLT_3_2V)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_CONNECTED;
        }
    }

    if (status != context->pilot_status.pilot_status_gbt18487_a)
    {
        LOG_ALERT("[%d][%d(0.01V)]%s->%s", context->tag, volt_value, enum_names_OpenChaoJi_pilot_status_gbt18487_a(context->pilot_status.pilot_status_gbt18487_a), enum_names_OpenChaoJi_pilot_status_gbt18487_a(status));
        context->pilot_status.pilot_status_gbt18487_a = status;
    }
    if (volt_value != context->voltage_checkpoint_1)
    {
        LOG_ALERT("[%d]VOLT_CHECKPOINT_1 %d->%d(0.01V)", context->tag, context->voltage_checkpoint_1, volt_value);
        context->voltage_checkpoint_1 = volt_value;
    }

    return status;
}
#endif
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
enum OpenChaoJi_pilot_status_gbt18487_b OpenChaoJi_secc_utility_pilot_status_b(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    enum OpenChaoJi_pilot_status_gbt18487_b status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_UNKNOWN;
    int volt_value = 0;

    if(context == NULL)
    {
        return status;
    }

    if (OPENCHAOJI_SECC_GBT27930_TYPE_B == context->secc_gbt27930_type)
    {
        volt_value = OpenChaoJi_secc_hal_gbt_get_vol_checkpoint_1(context->hal_handle);

        if(volt_value >= SYSTEM_B_SECC_CHECKPOINT_1_A_MIN && volt_value < SYSTEM_B_SECC_CHECKPOINT_1_A_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_A;
        }
        // else if(volt_value >= SYSTEM_B_SECC_CHECKPOINT_1_AP_MIN && volt_value < SYSTEM_B_SECC_CHECKPOINT_1_AP_MAX)       // 实际上桩端无法区分出Ap/Ap，所以这里直接跳过
        // {
        //     status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_Ap;
        // }
        else if(volt_value >= SYSTEM_B_SECC_CHECKPOINT_1_B_MIN && volt_value < SYSTEM_B_SECC_CHECKPOINT_1_B_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_B;
        }
        else if(volt_value >= SYSTEM_B_SECC_CHECKPOINT_1_C_MIN && volt_value < SYSTEM_B_SECC_CHECKPOINT_1_C_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_C;
        }
        else if(volt_value >= SYSTEM_B_SECC_CHECKPOINT_1_D_MIN && volt_value < SYSTEM_B_SECC_CHECKPOINT_1_D_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_D;
        }
        else if(volt_value >= SYSTEM_B_SECC_CHECKPOINT_1_E_MIN && volt_value < SYSTEM_B_SECC_CHECKPOINT_1_E_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_E;
        }
    }

    if (status != context->pilot_status.pilot_status_gbt18487_b)
    {
        LOG_ALERT("[%d][%d(0.01V)]%s->%s", context->tag, volt_value, enum_names_OpenChaoJi_pilot_status_gbt18487_b(context->pilot_status.pilot_status_gbt18487_b), enum_names_OpenChaoJi_pilot_status_gbt18487_b(status));
        context->pilot_status.pilot_status_gbt18487_b = status;
    }
    if (volt_value != context->voltage_checkpoint_1)
    {
        LOG_ALERT("[%d]VOLT_CHECKPOINT_1 %d->%d(0.01V)", context->tag, context->voltage_checkpoint_1, volt_value);
        context->voltage_checkpoint_1 = volt_value;
    }

    return status;
}
#endif

// 枪头连接
bool OpenChaoJi_secc_utility_pilot_is_evcc_connected(struct OpenChaoJi_secc_context_utility_pilot * context)
{

    if(context == NULL)
    {
        return false;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if (OPENCHAOJI_SECC_GBT27930_TYPE_A == context->secc_gbt27930_type)
    {
        return (OpenChaoJi_secc_utility_pilot_status_a(context) == OPENCHAOJI_PILOT_STATUS_GBT18487_A_CONNECTED);
    }
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if (OPENCHAOJI_SECC_GBT27930_TYPE_B == context->secc_gbt27930_type)
    {
        enum OpenChaoJi_pilot_status_gbt18487_b status = OpenChaoJi_secc_utility_pilot_status_b(context);

        return (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_Ap)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_B)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_C)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_D)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_E);
    }
#endif
    return false;
}

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
// 充电机就绪/车辆未就绪
bool OpenChaoJi_secc_utility_pilot_b_is_evcc_permit_charge(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

    if (OPENCHAOJI_SECC_GBT27930_TYPE_B == context->secc_gbt27930_type)
    {
        enum OpenChaoJi_pilot_status_gbt18487_b status = OpenChaoJi_secc_utility_pilot_status_b(context);

        return (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_D)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_E);
    }

    return false;
}

// 充电机和车辆均允许充电
bool OpenChaoJi_secc_utility_pilot_b_is_all_permit_charge(struct OpenChaoJi_secc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

    if (OPENCHAOJI_SECC_GBT27930_TYPE_B == context->secc_gbt27930_type)
    {
        enum OpenChaoJi_pilot_status_gbt18487_b status = OpenChaoJi_secc_utility_pilot_status_b(context);

        return (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_D);
    }

    return false;
}

#endif
